import { storeModuleManage } from './module';
import { IStoreOptions } from '../interfaces/store.interface';
import Utils from '../utils';

// 每一条的内容
interface IContent<T> {
	module_id: string;
	create_time: number;
	key: string;
	content: T;
	expire_time?: number | null;
}

/**
 * 创建内容
 * @param key
 * @param value
 * @param expireTime
 * @returns
 */
function createDataContent<T>(
	id: string,
	key: string,
	value: T,
	expireTime?: number,
): IContent<T> {
	const now = Date.now();
	return {
		module_id: id,
		create_time: now,
		key: key,
		content: value,
		expire_time: expireTime ? now + expireTime : null,
	};
}

/**
 * Store implementation
 */
class Storage {
	constructor(options: IStoreOptions) {
		if (!options) {
			throw new Error('The option must be passed!');
		}
		const { id, prefix } = options;
		if (!id) {
			throw new Error('The option id must be passed!');
		}

		if (!prefix) {
			throw new Error('The option prefix must be passed!');
		}
		this.id = id;
		this.prefix = Utils.stringUnderline(prefix);
		this.expireAutoDelete = !!options.expireAutoDelete;
		this.defineProps = options.defineProps || [];

		// bind this
		this.autoClear = this.autoClear.bind(this);
	}

	// 唯一id
	id: string;

	// 命名空间前缀
	prefix: string;

	// 默认值
	defaultValue: null = null;

	// 过期后是否删除
	expireAutoDelete: boolean = true;

	// 值的定义
	defineProps: string[] = [];

	// store
	private store = window.localStorage;

	// 生成key
	private generatorKey(dataKey: string): string {
		return (
			Utils.stringUnderline(String(this.prefix)) +
			'_' +
			Utils.stringUnderline(dataKey)
		);
	}

	// 判断当前key是否为当前容器
	private checkKeyHasContext(key: string): boolean {
		return key.startsWith(this.prefix);
	}

	// 检查过期
	private checkExpire(expireTime: number): boolean {
		return expireTime <= Date.now();
	}

	// 检查定义
	private checkDefine(key: string) {
		if (this.defineProps.length === 0) return true;
		return this.defineProps.length > 0 && this.defineProps.includes(key);
	}

	private getContent(key?: string) {
		// 检测是否定义
	}

	/**
	 * 获取数据
	 * @param keys
	 */
	get(...keys: string[]): Object | any {
		const result: { [key: string]: any } = {};
		if (keys.length === 0) return null;
		keys.forEach((key: string) => {
			// 检测是否定义
			if (!this.checkDefine(key)) {
				console.error(
					`Storage：Module attribute value [${key}] is not defined. Please add the corresponding key in module defineProps`,
				);
			} else {
				const _key = this.generatorKey(key);
				if (this.checkKeyHasContext(_key)) {
					const value = this.store.getItem(_key);
					if (value) {
						const dataContent = Utils.isJson(value)
							? JSON.parse(value || '')
							: null;
						// 检查是否过期
						if (this.checkExpire(dataContent.expire_time)) {
							console.log(`store中[${_key}]已过期！`);
							result[key] = null;
							this.expireAutoDelete &&
								this.store.removeItem(_key);
						} else {
							result[key] = Utils.dGet(
								dataContent,
								'content',
								this.defaultValue,
							);
						}
					}
				}
			}
		});

		// 如果单个，直接返回值，否则返回对象
		if (keys.length === 1) {
			return result[keys[0]];
		}
		return result;
	}

	/**
	 * 获取后删除
	 * @param keys
	 * @returns
	 */
	getOnce(...keys: string[]): object | any {
		const result: { [key: string]: any } = {};
		Utils.forEach(keys, (key: string) => {
			if (!this.checkDefine(key)) {
				console.error(
					`Storage：Module attribute value [${key}] is not defined. Please add the corresponding key in module defineProps`,
				);
			} else {
				const data = this.get(key);
				result[key] = data;
				this.delete(key);
			}
		});
		return arguments.length === 1 ? result[keys[0]] : result;
	}

	/**
	 * 设置数据
	 * @param key
	 * @param value
	 * @param expireTime
	 */
	set(
		key: object,
		value?: any,
		expireTime?: number,
	): { [key: string]: IContent<any> };
	set(key: string, value: any, expireTime?: number): IContent<any>;
	set(
		key: string | object,
		value?: any,
		expireTime?: number,
	): { [key: string]: IContent<any> } | IContent<any> {
		let data: { [key: string]: any } = {};
		if (typeof key === 'string') {
			data[key] = value;
		}
		if (typeof key === 'object' && Utils.getType(key) === 'object') {
			data = key;
		}
		const setDataRes: { [key: string]: any } = {};
		Utils.forEach(data, (val, k) => {
			// 检测定义
			if (!this.checkDefine(String(k))) {
				console.error(
					`Storage：Module attribute value [${key}] is not defined. Please add the corresponding key in module defineProps`,
				);
			} else {
				const storeKey: string = this.generatorKey(String(k));
				const dataContent = createDataContent(
					this.id,
					storeKey,
					val,
					expireTime,
				);
				this.store.setItem(storeKey, JSON.stringify(dataContent));
				setDataRes[k] = dataContent;
			}
		});
		return typeof key === 'string' ? setDataRes[key] : setDataRes;
	}

	/**
	 * 删除数据
	 * @param keys
	 */
	delete(...keys: string[]): Storage {
		Utils.forEach(keys, (key) => {
			this.store.removeItem(key);
		});
		return this;
	}

	/**
	 * 获取数量
	 * @returns
	 */
	getSize(): number {
		return this.getKeys().length;
	}

	/**
	 * 设置过期时间
	 * @param {number} expireTime
	 */
	setExpire(key: string, expireTime: number): number | null;
	setExpire(
		key: object,
		expireTime?: number,
	): { [key: string]: number | null };
	setExpire(
		key: string | object,
		expireTime?: number,
	): object | number | null {
		if (typeof key === 'string' && expireTime) {
			const data = this.get(key);
			if (!this.get(key)) {
				return null;
			}
			const { expire_time } = this.set(key, data, expireTime);
			return expire_time ? expire_time : null;
		} else {
			return {};
		}
	}

	/**
	 * 获取所有keys
	 * @returns
	 */
	getKeys(): string[] {
		const keys = Object.getOwnPropertyNames.call(null, localStorage);
		const storeKeys: string[] = [];
		Utils.forEach(keys, (key: string) => {
			if (this.checkKeyHasContext(key)) {
				storeKeys.push(key);
			}
		});
		return storeKeys;
	}

	// 自动删除
	autoClear(): void {
		const storeKeys: string[] = this.getKeys();
		Utils.forEach(storeKeys, (key: string) => {
			const value: string | null = this.store.getItem(key);
			const dataContent = Utils.isJson(value)
				? JSON.parse(value || '')
				: null;
			// 检查是否过期
			if (this.checkExpire(dataContent.expire_time)) {
				this.delete(key);
				console.warn(`Storage: ${this.id}.${key} auto clear`);
			}
		});
	}
}

export { Storage };
